package com.example.mapping.manage;

import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.example.mapping.common.exception.MappingBizException;
import com.example.mapping.constant.Constants;
import com.example.mapping.convert.*;
import com.example.mapping.domain.*;
import com.example.mapping.dto.FieldMappingDto;
import com.example.mapping.dto.FlowModelDto;
import com.example.mapping.dto.FlowModelQueryDto;
import com.example.mapping.sevice.*;
import com.example.mapping.utils.CommonUtils;
import com.example.mapping.utils.Tuple3;
import com.example.mapping.vo.*;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.example.mapping.common.exception.MappingErrorCodeEnum.*;

/**
 * 流程manage层
 *
 * @author baoyoujia
 */
@Component
public class FlowModelManage {

    @Autowired
    private FlowModelService flowModelService;

    @Autowired
    private DictService dictService;

    @Autowired
    private RuleService ruleService;

    @Autowired
    private FieldMappingService fieldMappingService;

    @Autowired
    private ValueMappingService valueMappingService;

    @Autowired
    private ValueMappingConvert valueMappinConvert;

    @Autowired
    private FlowModelConvert flowModelConvert;

    @Autowired
    private FieldMappingConvert fieldMappingConvert;

    @Autowired
    private DictConvert dictConvert;

    @Autowired
    private RuleConvert ruleConvert;

    /**
     * 分页获取流程信息
     *
     * @param flowModelQueryDto 流程查询Dto
     * @return 流程Dto信息
     */
    public PageDTO<FlowModelVo> getFlowByPage(FlowModelQueryDto flowModelQueryDto) {
        PageDTO<FlowModel> pageDTO = new PageDTO<>();
        pageDTO.setCurrent(flowModelQueryDto.getCurrent());
        pageDTO.setSize(flowModelQueryDto.getSize());
        PageDTO<FlowModel> flowModelPage = flowModelService.page(pageDTO);
        if (CollectionUtils.isEmpty(flowModelPage.getRecords())) {
            return new PageDTO<>();
        }
        // 转换pageVo
        PageDTO<FlowModelVo> flowModelVoPage = flowModelConvert.modelPage2Vo(flowModelPage);
        // 获取本页所有的flowId
        List<Long> flowIds = flowModelVoPage.getRecords().stream().map(BaseVo::getId).collect(Collectors.toList());

        // 获取所有的字段映射信息
        List<FieldMapping> fieldMappingByFlowList = fieldMappingService.getFieldMappingByFlowIds(flowIds);
        List<FieldMappingVo> fieldMappingVoList = fieldMappingConvert.model2Vo(fieldMappingByFlowList);
        // 构建流程和字段映射的map
        Tuple3<Map<Long, Dict>, Map<Long, Rule>, Map<Long, ValueMapping>> dictAndRuleAndValueMapping = getDictAndRuleAndValueMapping(fieldMappingVoList);
        Map<Long, List<FieldMappingVo>> flowToFieldMap = fieldMappingVoList.stream().collect(Collectors.groupingBy(FieldMappingVo::getFlowId));

        for (FlowModelVo flowModelVo : flowModelVoPage.getRecords()) {
            List<FieldMappingVo> fieldMappingVos = flowToFieldMap.getOrDefault(flowModelVo.getId(), Lists.newArrayList());
            if (CollectionUtils.isEmpty(fieldMappingVos)) {
                continue;
            }
            for (FieldMappingVo fieldMappingVo : fieldMappingVos) {
                fillFieldMappingVo(dictAndRuleAndValueMapping, fieldMappingVo);
            }
            flowModelVo.setFieldMappings(fieldMappingVos);
        }
        return flowModelVoPage;
    }

    /**
     * 删除流程
     *
     * @param id 流程ID
     * @return 删除结果
     */
    public Boolean delFlow(Long id) {
        FlowModel flowModel = flowModelService.getById(id);
        flowModel.setSysDelete(Constants.Number.INT_2);
        boolean result = flowModelService.updateById(flowModel);
        if (!result) {
            throw new MappingBizException(DEL_FLOW_ERROR);
        }

        result = removeOldFiledMapping(flowModel.getId());
        if (!result) {
            throw new MappingBizException(DEL_FLOW_ERROR);
        }
        return true;
    }

    /**
     * 修改流程
     *
     * @param flowModelDto 流程信息Dto
     * @return 修改结果
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean editFlow(FlowModelDto flowModelDto) {
        FlowModel flowModel = flowModelConvert.dto2Model(flowModelDto);
        flowModelService.updateById(flowModel);
        boolean result = removeOldFiledMapping(flowModel.getId());
        if (!result) {
            throw new MappingBizException(EDIT_FLOW_ERROR);
        }

        result = addNewFieldMapping(flowModelDto.getFieldMappingDtoList());
        if (!result) {
            throw new MappingBizException(EDIT_FLOW_ERROR);
        }
        return true;
    }

    /**
     * 新增流程
     *
     * @param flowModelDto 新增流程Dto
     * @return 新增结果
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean addFlow(FlowModelDto flowModelDto) {
        FlowModel flowModel = flowModelConvert.dto2Model(flowModelDto);
        boolean result = flowModelService.save(flowModel);
        if (!result) {
            throw new MappingBizException(ADD_FLOW_ERROR);
        }
        result = addNewFieldMapping(flowModelDto.getFieldMappingDtoList());
        if (!result) {
            throw new MappingBizException(ADD_FLOW_ERROR);
        }
        return true;
    }

    /**
     * 获取流程详情
     *
     * @param id 流程ID
     * @return 流程信息
     */
    public FlowModelVo getFlow(Long id) {
        FlowModel flowModel = flowModelService.getById(id);
        if (Objects.isNull(flowModel)) {
            return new FlowModelVo();
        }
        FlowModelVo flowModelVo = flowModelConvert.model2Vo(flowModel);

        List<FieldMapping> fieldMappingList = fieldMappingService.getFieldMappingByFlowId(id);
        List<FieldMappingVo> fieldMappingVoList = fieldMappingConvert.model2Vo(fieldMappingList);

        // 构建流程和字段映射的map
        Tuple3<Map<Long, Dict>, Map<Long, Rule>, Map<Long, ValueMapping>> dictAndRuleAndValueMapping = getDictAndRuleAndValueMapping(fieldMappingVoList);

        for (FieldMappingVo fieldMappingVo : fieldMappingVoList) {
            fillFieldMappingVo(dictAndRuleAndValueMapping, fieldMappingVo);
        }
        flowModelVo.setFieldMappings(fieldMappingVoList);
        return flowModelVo;
    }

    /**
     * 删除老的字段映射信息
     *
     * @param flowId 流程ID
     * @return 删除结果
     */
    private boolean removeOldFiledMapping(Long flowId) {
        List<FieldMapping> oldFieldMappingList = fieldMappingService.getFieldMappingByFlowId(flowId);
        oldFieldMappingList.forEach(x -> x.setSysDelete(Constants.Number.INT_2));
        return fieldMappingService.updateBatch(oldFieldMappingList) > 0;
    }

    /**
     * 添加新的字段映射信息
     *
     * @param fieldMappingDtoList 字段映射集合
     * @return 删除结果
     */
    private boolean addNewFieldMapping(List<FieldMappingDto> fieldMappingDtoList) {
        List<FieldMapping> fieldMappingList = fieldMappingDtoList.stream().map(fieldMappingDto -> {
            FieldMapping fieldMapping = fieldMappingConvert.dto2Model(fieldMappingDto);
            fieldMapping.setRuleIds(CommonUtils.list2Str(fieldMappingDto.getRuleIdList(), Constants.Symbol.COMMA));
            fieldMapping.setValueMappingIds(CommonUtils.list2Str(fieldMappingDto.getValueMappingIdList(), Constants.Symbol.COMMA));
            return fieldMapping;
        }).collect(Collectors.toList());
        return fieldMappingService.saveBatch(fieldMappingList);
    }

    /**
     * 填充字段映射Vo类
     *
     * @param dictAndRuleAndValueMapping 映射
     * @param fieldMappingVo             字段映射Vo
     */
    private void fillFieldMappingVo(Tuple3<Map<Long, Dict>, Map<Long, Rule>, Map<Long, ValueMapping>> dictAndRuleAndValueMapping, FieldMappingVo fieldMappingVo) {
        Dict dict = dictAndRuleAndValueMapping.getOne().getOrDefault(fieldMappingVo.getDictId(), new Dict());
        DictVo dictVo = dictConvert.model2Vo(dict);
        fieldMappingVo.setDictVo(dictVo);

        List<Rule> ruleList = Arrays.stream(Optional.ofNullable(fieldMappingVo.getRuleIds()).orElse(Constants.Symbol.EMPTY).split(Constants.Symbol.COMMA)).filter(x -> !StringUtils.isEmpty(x)).map(x -> dictAndRuleAndValueMapping.getTwo().getOrDefault(Long.parseLong(x)
                , new Rule())).collect(Collectors.toList());
        List<RuleVo> ruleVoList = ruleConvert.model2Vo(ruleList);
        fieldMappingVo.setRuleInfoList(ruleVoList);

        List<ValueMapping> valueMappingList = Arrays.stream(fieldMappingVo.getValueMappingIds().split(Constants.Symbol.COMMA)).filter(x -> !StringUtils.isEmpty(x)).map(x -> dictAndRuleAndValueMapping.getThree().getOrDefault(Long.parseLong(x)
                , new ValueMapping())).collect(Collectors.toList());
        List<ValueMappingVo> valueMappingVoList = valueMappinConvert.model2Vo(valueMappingList);
        fieldMappingVo.setValueMappingVoList(valueMappingVoList);
    }

    /**
     * 获取字典和校验规则
     *
     * @param fieldMappingVoList 字段映射Dto
     * @return 字典和校验规则
     */
    public Tuple3<Map<Long, Dict>, Map<Long, Rule>, Map<Long, ValueMapping>> getDictAndRuleAndValueMapping(List<FieldMappingVo> fieldMappingVoList) {
        // 获取字段上的字典
        Map<Long, Dict> dictMap = Maps.newHashMap();
        Map<Long, Rule> ruleMap = Maps.newHashMap();
        Map<Long, ValueMapping> valeMappingMap = Maps.newHashMap();
        List<Long> dictIds = fieldMappingVoList.stream().map(FieldMappingVo::getDictId).filter(dictId -> !Constants.Number.LONG_0.equals(dictId)).distinct().collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(dictIds)) {
            dictMap = dictService.getDictByIds(dictIds).stream().collect(Collectors.toMap(Dict::getId, Function.identity(), (x, y) -> x));
        }

        // 获取字段上的规则
        List<Long> ruleIds = fieldMappingVoList.stream().map(FieldMappingVo::getRuleIds).filter(x -> !StringUtils.isEmpty(x)).map(x -> x.split(Constants.Symbol.COMMA)).map(x -> Arrays.stream(x).collect(Collectors.toList())).flatMap(Collection::stream).map(Long::parseLong).distinct().collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(dictIds)) {
            ruleMap = ruleService.getRuleByIds(ruleIds).stream().collect(Collectors.toMap(Rule::getId, Function.identity(), (x, y) -> x));
        }

        // 获取字段上的值映射
        List<Long> valueMappingIds = fieldMappingVoList.stream().map(FieldMappingVo::getValueMappingIds).filter(x -> !StringUtils.isEmpty(x)).map(x -> x.split(Constants.Symbol.COMMA)).map(x -> Arrays.stream(x).collect(Collectors.toList())).flatMap(Collection::stream).map(Long::parseLong).distinct().collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(valueMappingIds)) {
            valeMappingMap = valueMappingService.getValueMappingByIds(valueMappingIds).stream().collect(Collectors.toMap(ValueMapping::getId, Function.identity(), (x, y) -> x));
        }
        return Tuple3.of(dictMap, ruleMap, valeMappingMap);
    }
}
